#include "ThreadPool.hpp"

void ThreadPool::Init(){
    cout << "Init ThreadPool" << endl;
    PoolClose = false;
    pthread_mutex_init(&TasksLock, nullptr);
    pthread_cond_init(&TasksNotEmpty, nullptr);
    pthread_cond_init(&NoTasks, nullptr);

    for (int i = 0; i < THREAD_NUM; ++i){
        pthread_t tmp;
        pthread_create(&tmp, nullptr, thread_function, (void *)this);
        Pthreads.push_back(tmp);
    }
}

void* ThreadPool::thread_function(void* arg){
    ThreadPool *pool = (ThreadPool *)arg;
    while(1){
        pthread_mutex_lock(&pool->TasksLock);

        // 进入临界区
        while(pool->Tasks.empty() && pool->PoolClose == false){
            pthread_cond_wait(&pool->TasksNotEmpty, &pool->TasksLock);
        }
        if(pool->Tasks.empty() && pool->PoolClose == true){
            pthread_cond_signal(&pool->NoTasks);
            pthread_mutex_unlock(&pool->TasksLock);
            pthread_exit(nullptr);
        }
        Task *curTask = pool->Tasks.front();
        if(curTask == nullptr){
            cout << "Fuck" << endl;
        }
        pool->Tasks.pop();

        // 临界区结束
        pthread_mutex_unlock(&pool->TasksLock);

        // 一定要解了锁再执行任务，否则就特么不是并行了。
        curTask->run();
        delete curTask;
        curTask = nullptr;
    }
}

int ThreadPool::add_job(void (*callback_function)(void* arg), void *arg){
    pthread_mutex_lock(&TasksLock);
    
    // 进入临界区(不再限制任务队列的长度)
    if(PoolClose == true){
        pthread_mutex_unlock(&TasksLock);
        return -1;
    }
    Task *pTask = new Task(callback_function, arg);
    Tasks.push(pTask);
    pthread_cond_signal(&TasksNotEmpty);
    // 离开临界区

    pthread_mutex_unlock(&TasksLock);
    return 0;
}

int ThreadPool::destroy()
{
    pthread_mutex_lock(&TasksLock);

    while(!Tasks.empty()){
        pthread_cond_wait(&NoTasks, &TasksLock);
    }

    pthread_mutex_unlock(&TasksLock);

    pthread_cond_broadcast(&TasksNotEmpty);
    for (int i = 0; i < Pthreads.size(); ++i){
        pthread_join(Pthreads[i], nullptr);
    }
    pthread_mutex_destroy(&TasksLock);
    pthread_cond_destroy(&NoTasks);
    pthread_cond_destroy(&TasksNotEmpty);
    return 0;
}
